<?php

/*
 * This file is part of PHP CS Fixer.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *     Dariusz Rumiński <dariusz.ruminski@gmail.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

use app\wechat\service\FansService;
use app\wechat\service\WechatService;
use think\facade\Cache;
use think\facade\Session;
use think\Request;
use WeChat\Oauth;

error_reporting(E_ERROR | E_PARSE );

function xml_to_array($xml)
{
    $reg = '/<(\\w+)[^>]*?>([\\x00-\\xFF]*?)<\\/\\1>/';
    if (preg_match_all($reg, $xml, $matches)) {
        $count = count($matches[0]);
        $arr = [];
        for ($i = 0; $i < $count; ++$i) {
            $key = $matches[1][$i];
            $val = xml_to_array($matches[2][$i]); // 递归
            if (array_key_exists($key, $arr)) {
                if (is_array($arr[$key])) {
                    if (!array_key_exists(0, $arr[$key])) {
                        $arr[$key] = [
                            $arr[$key],
                        ];
                    }
                } else {
                    $arr[$key] = [
                        $arr[$key],
                    ];
                }
                $arr[$key][] = $val;
            } else {
                $arr[$key] = $val;
            }
        }

        return $arr;
    }

    return $xml;
}

// Xml 转 数组, 不包括根键
function xmltoarray($xml)
{
    $arr = xml_to_array($xml);
    $key = array_keys($arr);

    return $arr[$key[0]];
}

function get_name_by_status($table = '', $field = '', $value = null)
{
    $status_obj = new \app\common\service\SystemDict();
    return $status_obj->getInfo($table, $field, $value);
}

/**
 * 输出JSON
 *
 * @param int        $code 状态码
 * @param string|int $msg  描述
 * @param mixed      $data 返回数据
 * @param bool       $type 是否输出或返回
 *
 * @return string json后的字符串
 */
function json_return($code, $msg, $data = [], $type = false)
{
    $json = json_encode([
                            'code' => $code,
                            'msg'  => $msg,
                            'data' => $data,
                        ]);

    # 直接返回
    if ($type) {
        return $json;
    }
    # 直接输出
    echo $json;
    exit;
}

//判断是否是json;
function is_json($data = '', $assoc = false)
{
    $data = json_decode($data, $assoc);
    if ($data && (is_object($data)) || (is_array($data) && !empty(current($data)))) {
        return $data;
    }
    return false;
}

/**
 *时间戳 转   日期格式 ： 精确到毫秒，x代表毫秒
 */
function get_microtime_format($time)
{
    if (strstr($time, '.')) {
        sprintf("%01.3f", $time); //小数点。不足三位补0
        list($usec, $sec) = explode(".", $time);
        $sec = str_pad($sec, 3, "0", STR_PAD_RIGHT); //不足3位。右边补0
    } else {
        $usec = $time;
        $sec = "000";
    }
    $date = date("Y-m-d H:i:s.x", $usec);
    return str_replace('x', $sec, $date);
}

/**
 * 求两个日期之间相差的天数
 * (针对1970年1月1日之后，求之前可以采用泰勒公式)
 *
 * @param string $day1
 * @param string $day2
 *
 * @return number
 */
function diffBetweenTwoDays($day1, $day2)
{
    $second1 = strtotime($day1);
    $second2 = strtotime($day2);

    if ($second1 < $second2) {
        $tmp = $second2;
        $second2 = $second1;
        $second1 = $tmp;
    }
    return ($second1 - $second2) / 86400;
}

/** 时间日期转时间戳格式，精确到毫秒，
 *
 */
function get_data_format($time)
{
    list($usec, $sec) = explode(".", $time);
    $date = strtotime($usec);
    $return_data = str_pad($date . $sec, 13, "0", STR_PAD_RIGHT); //不足13位。右边补0
    return $return_data;
}

function dataMap($_map, $data)
{
    $res = [];
    foreach ($_map as $key => $val) {
        (isset($data[$key])) && $res[$val] = $data[$key];
    }

    return $res;
}

function getMemberInfo($id)
{
    $data = db('member')->find($id);
    $crm = \app\common\lib\Factory::createCrm();
    $data['openid'] = getOpenidByMid($id);
    if ($crm->getMemberInfo(['openid' => $data['openid']])) {
        $data['crm'] = $crm->getResponse();
    };
    return $data;
}

////获取openid
function getOpenidByMid($mid , $update =false)
{
    $key = 'MEMBER_OPENID:'.$mid;
    $openid = Cache::get($key);
    if($openid ===false || $update){
        $uid = db('member_user')
            ->where('mid', $mid)
            ->where('type', 'wechat')
            ->where('status', 0)
            ->value('uid');
        $user = db('wechat_fans')->find($uid);
        Cache::set($key , $user['openid'] , 3600);
    }
    return $openid;
}
//获取本地会员信息
function getLocalMember($mid , $update = false){
    $key = 'MEMBER_INFO:'.$mid;
    $data = Cache::get($key);
    if($data === false || $update ){
        $data = db('member')->find($mid);
        Cache::set($key , $data , 600);
    }
    return $data;
}

function getMemberInfoByOpenid($openid)
{
    $user = \app\api\model\WechatFans::get(['openid' => $openid]);
    if (!$user) return false;
    $memberUser = \app\common\model\MemberUser::order('id desc')
                                              ->get(['uid' => $user['id']]);
    if (!$memberUser) return false;
    return getMemberInfo($memberUser['mid']);
}

/**
 * 加密原通联券号
 *
 * @param string $p_barcode 原通联券号
 *
 * @return string
 */
function encrypt($p_barcode)
{
    $lPre = '89';
    $random_number = rand(1000, 9999);
    $newNo = intval($p_barcode) + $random_number * $random_number;

    $vouNo = $lPre . $newNo . $random_number;
    $lenght = strlen($random_number);
    $vouNO = $vouNo . $lenght . fMakeVerify($newNo);
    return $vouNO;
}

/**
 * 解密通联券号
 *
 * @param string $p_barcode 待解密通联券号
 *
 * @return string
 */
function decrypt($p_barcode)
{
    $lPre = '89';
    $r_len = substr($p_barcode, -2, 1);

    $vouNo = substr($p_barcode, 2, strlen($p_barcode) - $r_len - 1 - 2 - 1);

    $random_number = substr($p_barcode, -2 - $r_len, $r_len);

    $newNo = $vouNo - $random_number * $random_number;

    return $newNo;
}


/**
 * @param int $num
 *
 * @return int|string
 */
function fMakeVerify($num = 111)
{

    if ($num === null || $num <= 0) {
        $lVerify = 0;
    } else {
        $lVerify = 0;
        $llen = strlen($num);
        for ($i = 1; $i <= $llen; $i++) {
            if ($i % 2 == 1) {
                $lVerify += (substr($num, $i, 1) + 0);
            } else {
                $lVerify += (substr($num, $i, 1) + 0) * 3;
            }
        }
        $lVerify = (10 - $lVerify % 10) % 10;
    }
    return $lVerify;
}

//前端模块代码生成
function createTmp($category_id)
{
    $category = db('cms_category')->find($category_id);
    if ($category['child_type'] === 'module') {
        $data = getModuleData($category['module']);
    } else {
        $data = db('cms_category')
            ->where('status' ,1)
            ->where('pid', $category_id)
            ->order('sort asc')
            ->select();
    }
    return $data;
//    $category['sub'] = $data;
//    return $category;
    //获取当前类型的HTML代码
    $class = \app\common\lib\Factory::createTmp('tmp\Tmp' . $category['type']);
    return $class->tmp($category);
}

function getModuleData($id)
{
    $module = db('cms_module')->find($id);
    $module_obj = new \app\admin\controller\theme\Module();
    $action = "{$module['module_content_source']}";
    if (!$action) return [];
    try {
        return $module_obj->$action($module['param']);
    } catch (\Exception $e) {
        return [];
    }
}


function get_openid($update = false)
{
    //session('openid' ,'111222222');
    //session('openid' ,'oir2e5nZou2bMUto_xc6ELRjYAVw');

    $openid_session = session('openid');
    if (!$update) {
        if ($openid_session) return $openid_session;
    }
    $oauth = WechatService::WeChatOauth();
    if (request()->param('state') !== 'WeChat') {
        $url = $oauth->getOauthRedirect(url('', '', '', true), 'WeChat');
        header('content-type:text/html;charset=uft-8');
        header('location:'.$url); exit;
    } else {
        if (empty (request()->param('code'))) {
            exit ('code获取失败');
        }
        $info = $oauth->getOauthAccessToken();
        if ($info && isset($info['openid'])) {
            session('openid', $info['openid']);
            $flag = db('wechat_fans')->where('openid' , $info['openid'])->find();
            updateFansInfo($info['openid'],$flag);
            //更新或修改微信粉丝信息
        }else{
            Session::delete('openid');
        }
        return $info['openid'] ?: '';
    }

}

function updateFansInfo($openid, $subscribe = true)
{
    $user = WechatService::WeChatUser()
                         ->getUserInfo($openid);
    if ($subscribe) {
        try {
            return FansService::set($user);
        } catch (\Exception $e) {
            \think\facade\Log::error(__METHOD__ . " {$openid} 粉丝信息获取失败，{$e->getMessage()}");
            return false;
        }
    }
    return data_save('WechatFans', array_merge($user, ['appid' => config('wechat.appid')]), 'openid', ['appid' => config('wechat.appid')]);
}

//数值分割成数组
function num2Array($num)
{
    while ($num > 0) {

        $t = $num % 10;

        $num = intval($num / 10);

        $b[] = $t;

    }

    $b = array_reverse($b);
    return $b ?:[0];
}

/**
 * 获取模板消息模板
 *
 * @param      $type
 * @param bool $update
 *
 * @return array|mixed|PDOStatement|string|\think\Model|null
 * @throws \think\db\exception\DataNotFoundException
 * @throws \think\db\exception\ModelNotFoundException
 * @throws \think\exception\DbException
 * @author : Randy_chen
 * @Date   : 2019/7/31
 * @Time   : 23:01
 */
function getTempInfo($type, $update = false)
{
    $info = Cache::get('TEMP_' . $type);

    if ($info === false || $update === true) {
        $where['type'] = $type;
        $info = db('wechat_message_template')
            ->where($where)
            ->find();
        Cache::set('TEMP_' . $type, $info, 1800);
    }

    return $info;
}

/**
 * @param $arr
 *
 * @return array
 */
function getValues($arr, $preg = '/{(.*?)}/')
{
    $res = getValue($arr, $preg);
    $result = getOneValue($res);

    return $result;
}

/**
 * @param $res
 *
 * @return array
 */
function getOneValue($res)
{
    static $arr = [];
    foreach ($res as $v) {
        if (is_array($v)) {
            getOneValue($v);
        } else {
            $arr[] = $v;
        }
    }

    return $arr;
}

/**
 * 模板消息参数正则替换
 *
 * @param $arr
 *
 * @return array
 */
function getValue($arr, $preg)
{
    static $array = [];
    foreach ($arr as $v) {
        if (is_array($v)) {
            getValue($v, $preg);
        } else {

            preg_match_all($preg, $v, $value);

            if ($value[0]) {

                $array[] = array_values($value[0]);
            }
        }
    }

    return $array;
}

/**
 * 数据加解密
 *
 * @param string $string    需要加解密的数据
 * @param bool   $operation 是否解密，false|true
 * @param string $key       加解密秘钥
 * @param int    $expiry    数据失效时间
 *
 * @return string 加解密后的字符串
 */
function dec_encrypt($string, $operation = true, $key, $expiry = 0)
{
    # 动态密匙长度，相同的明文会生成不同密文就是依靠动态密匙
    $ckey_length = 4;
    # 密匙
    $key = md5($key);  //md5加密秘钥
    # 密匙a会参与加解密

    $keya = md5(substr($key, 0, 16));  //秘钥a  md5加密  md5生成key的前16位.
    # 密匙b会用来做数据完整性验证

    $keyb = md5(substr($key, 16, 16));
    # 密匙c用于变化生成的密文
    $keyc = $ckey_length ? ($operation == true ? substr($string, 0, $ckey_length) : substr(md5(microtime()), -$ckey_length)) : '';

    # 参与运算的密匙
    $cryptkey = $keya . md5($keya . $keyc);
    $key_length = strlen($cryptkey);
    # 明文，前10位用来保存时间戳，解密时验证数据有效性，10到26位用来保存$keyb(密匙b)，
    # 解密时会通过这个密匙验证数据完整性
    # 如果是解码的话，会从第$ckey_length位开始，因为密文前$ckey_length位保存 动态密匙，以保证解密正确

    $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string;
    $string_length = strlen($string);
    $result = '';
    $box = range(0, 255);
    $rndkey = [];

    # 产生密匙簿
    for ($i = 0; $i <= 255; $i++) {
        $rndkey[$i] = ord($cryptkey[$i % $key_length]);
    }

    # 用固定的算法，打乱密匙簿，增加随机性，好像很复杂，实际上对并不会增加密文的强度
    for ($j = $i = 0; $i < 256; $i++) {
        $j = ($j + $box[$i] + $rndkey[$i]) % 256;
        $tmp = $box[$i];
        $box[$i] = $box[$j];
        $box[$j] = $tmp;
    }

    # 核心加解密部分
    for ($a = $j = $i = 0; $i < $string_length; $i++) {
        $a = ($a + 1) % 256;
        $j = ($j + $box[$a]) % 256;
        $tmp = $box[$a];
        $box[$a] = $box[$j];
        $box[$j] = $tmp;
        # 从密匙簿得出密匙进行异或，再转成字符
        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
    }

    if ($operation == true) {
        # 验证数据有效性，请看未加密明文的格式
        if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
            return substr($result, 26);
        } else {
            return '';
        }
    } else {
        # 把动态密匙保存在密文里，这也是为什么同样的明文，生产不同密文后能解密的原因
        # 因为加密后的密文可能是一些特殊字符，复制过程可能会丢失，所以用base64编码
        return $keyc . str_replace('=', '', base64_encode($result));
    }
}

function unicode_decode($unicode_str)
{
    $json = '{"str":"' . $unicode_str . '"}';
    $arr = json_decode($json, true);
    if (empty($arr)) return '';
    return $arr['str'];
}

/**
 *
 * @param      $uid
 * @param bool $update
 *
 * @return bool|mixed
 * @author : Randy_chen
 * @Date   : 2019/8/22
 * @Time   : 17:45
 */
function getUserInfo($uid, $update = false)
{
    if (!$uid) return false;
    $key = 'wechat_fans:' . $uid;
    $user = Cache::get($key);
    if ($user === false || $update) {
        $userObj = \app\api\model\WechatFans::get($uid);
        if ($userObj) {
            $user = $userObj->getData();
            Cache::set($key, $user, 600);
        }
    }
    return $user;
}

/**
 *
 * @param      $openid
 * @param bool $update
 *
 * @return bool|mixed
 * @author : Randy_chen
 * @Date   : 2019/8/22
 * @Time   : 17:46
 */
function getUserInfoByOpenid($openid, $update = false)
{
    if (!$openid) return false;
    $key = 'wechat_fans_openid:' . $openid;
    $user = Cache::get($key);
    if ($user === false || $update) {
        $where['openid'] = $openid;
        $userObj = \app\api\model\WechatFans::get($where);
        if ($userObj) {
            $user = $userObj->getData();
            Cache::set($key, $user, 600);
        }
    }
    return $user;
}

/**
 * 获取指定日期段内每一天的日期
 *
 * @param Date $startdate 开始日期
 * @param Date $enddate   结束日期
 *
 * @return Array
 */
function getDateFromRange($startdate, $enddate)
{

    $stimestamp = strtotime($startdate);
    $etimestamp = strtotime($enddate);

    // 计算日期段内有多少天
    $days = ($etimestamp - $stimestamp) / 86400 + 1;

    // 保存每天日期
    $date = [];

    for ($i = 0; $i < $days; $i++) {
        $date[] = date('Y-m-d', $stimestamp + (86400 * $i));
    }

    return $date;
}

function log1($message , $scane){
    $data['add_time'] = date('Y-m-d H:i:s');
    $data['message'] = $message;
    $data['scane'] = $scane;
    db('log')->insert($data);

}
